package com.graduation.smartparkingplatform.WebSocket;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * @author skygray
 * @date 2021-12-18
 */
@ServerEndpoint(value = "/websocket") // 这里是前端访问地址时需要带的。
@Component
@Slf4j
public class WebSocket {

  private static RedisTemplate redisTemplate;
  // 注入的时候，给类的 service 注入
  @Autowired
  public void setRedisService(RedisTemplate redisTemplate) {
    WebSocket.redisTemplate = redisTemplate;
  }
  // 上面这么写的原因是因为直接用   @Autowired注入会导致 homePageMapper未null 注入不成功，所以需要这么去写。具体原因可去百度其他文档
  // 其实这里还可以  写一个连接数的静态变量，当每次连接成功后 ++一次，断开连接时 -- 一次，可以实时观测连接数，根据具体需求去做就可以了
  // concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
  private static CopyOnWriteArraySet<WebSocket> webSocketSet = new CopyOnWriteArraySet<WebSocket>();

  // private volatile static List<Session> sessions = Collections.synchronizedList(new ArrayList());
  private Session session;
  /** 连接建立成功调用的方法 */
  @OnOpen
  public void onOpen(Session session) {
    this.session = session;
    webSocketSet.add(this); // 将连接添加到安全的线池去
    log.info("WebSocket connect");
  }

  /** 连接关闭调用的方法 */
  @OnClose
  public void onClose() {
    log.info("WebSocket close");
  }

  public void sendOneMessage(String message) {
    /*在发送数据之前先确认 session是否已经打开 使用session.isOpen() 为true 则发送消息
     * 不然会报错:The WebSocket session [0] has been closed and no method (apart from close()) may be called on a closed session */
    if (session != null && session.isOpen()) {
      try {
        session.getAsyncRemote().sendText(message);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }

  /**
   * 给前台推消息
   *
   * @param session
   * @param rs
   * @throws IOException
   */
  public void sendMessage(String rs) throws IOException {
    if (this.session.isOpen()) { // 判断session是否是打开状态的，打开状态的才发。
      this.session.getBasicRemote().sendText(rs);
    }
  }
  // 下面这个方法是对外提供的静态方法，当业务层需要给改变前端显示内容，或给前端推送内容时调用此方法（可根据具体业务逻辑更改此方法）
  public static void sendInfo(String message) throws IOException {
    //    List<user> hhlist = userMapper.findUsers();
    //    String json = hhlist.toString();
    //    String json = Result.of(200, "得到实时数据成功").put("hhlist", hhlist).json();
    for (WebSocket item : webSocketSet) { // 这是默认给全部的连接发送消息   如果不需要给全部发，可以定义一个变量来区别每次链接的ID 给对应的ID发
      item.sendMessage(message);
    }
  }

  /**
   * 收到前端客户端消息后调用的方方法
   *
   * @param message 客户端发送过来的消息
   */
  @OnMessage
  public void onMessage(String message, Session session) {
    System.out.println("来自客户端的消息:" + message);
  }

  /** 发生异常时调用 */
  @OnError
  public void onError(Session session, Throwable error) {
    log.error("WebSocket error-" + error);
    error.printStackTrace();
  }
}
